package awk.script.javassist.method04.proxy.bytebuddy;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import static net.bytebuddy.matcher.ElementMatchers.*;

/**
 * @author yujianlong
 * @create 2021-03-29 17:16
 **/
public class ByteBuddyProxy {

	/***
	 * 直接获取代理对象 【对类内所有声明的方法有效】
	 *
	 * @author yujianlong
	 * @date 2021/3/29
	 * @return T
	 */
	public static <T> T getProxyObject(Class<T> clazz,Class<?>[] parameterTypes,Object[] initargs) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

		Class<T> tClass = getProxy(clazz);
		Constructor<T> constructor = tClass.getConstructor(parameterTypes);
		return constructor.newInstance(initargs);

	}

	/***
	 * 直接获取代理对象 【对指定的方法有效】
	 *
	 * @author yujianlong
	 * @date 2021/3/29
	 * @return T
	 */
	public static <T> T getProxyObj(Class<T> clazz,Class<?>[] parameterTypes,Object[] initargs,String methodName,Class[] MethodParaTypes) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

		Class<T> tClass = getProxy(clazz,methodName,MethodParaTypes);
		Constructor<T> constructor = tClass.getConstructor(parameterTypes);
		return constructor.newInstance(initargs);
	}

	/***
	 * 获取代理class
	 *
	 * @author yujianlong
	 * @date 2021/3/29
	 * @return T
	 */
	public static <T> Class<T> getProxy(Class<T> clazz) {

		DynamicType.Unloaded dynamicType = new ByteBuddy()
				.subclass(clazz)
				.method(isDeclaredBy(clazz))
//				.method(null != paraTypes ? named(methodName).and(takesArguments(paraTypes)) : named(methodName))
				.intercept(MethodDelegation.to(TargetInterceptor.class))
				.make();
		return (Class<T>) dynamicType.load(Thread.currentThread().getContextClassLoader()).getLoaded();

	}

	/***
	 * 获取代理class
	 *
	 * @author yujianlong
	 * @date 2021/3/29
	 * @return java.lang.Class<T>
	 */
	public static <T> Class<T> getProxy(Class<T> clazz,String methodName,Class[] MethodParaTypes) {

		DynamicType.Unloaded dynamicType = new ByteBuddy()
				.subclass(clazz)
//				.method(isDeclaredBy(clazz))
				.method(null != MethodParaTypes ? named(methodName).and(takesArguments(MethodParaTypes)) : named(methodName))
				.intercept(MethodDelegation.to(TargetInterceptor.class))
				.make();
		return (Class<T>) dynamicType.load(Thread.currentThread().getContextClassLoader()).getLoaded();

	}

}

